using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.EventSystems;
using Object = UnityEngine.Object;

namespace EntityKit.Runtime
{
    public static partial class BindService
    {
        private static readonly Dictionary<int, List<object>> s_BindedUIComponents = new Dictionary<int, List<object>>();
        private static readonly HashSet<int> s_BindedComponents = new HashSet<int>();

        private static readonly Dictionary<Type, FieldInfo[]> s_CachedFields = new Dictionary<Type, FieldInfo[]>();

        private static readonly Dictionary<Type, MethodInfo[]> s_CachedMethods = new Dictionary<Type, MethodInfo[]>();

        private static readonly Dictionary<string, Transform> s_PathCache = new Dictionary<string, Transform>();

        private static readonly Dictionary<string, Type> s_CachedTypes = new Dictionary<string, Type>
        {
            { "ComponentBindAttribute", typeof(ComponentBindAttribute) },
            { "GameObjectBindAttribute", typeof(GameObjectBindAttribute) },
            { "CollectionBindAttribute", typeof(CollectionBindAttribute) },
            
            { "UIButtonClickBindAttribute", typeof(UIButtonClickBindAttribute) },
            { "UIToggleValueChangedBindAttribute", typeof(UIToggleValueChangedBindAttribute) },
            { "UISliderValueChangedBindAttribute", typeof(UISliderValueChangedBindAttribute) },
            { "UIInputFieldValueChangedBindAttribute", typeof(UIInputFieldValueChangedBindAttribute) },
            { "UIDropdownValueChangedBindAttribute", typeof(UIDropdownValueChangedBindAttribute) },
            { "UILongClickBindAttribute", typeof(UILongClickBindAttribute) },
            { "UIDoubleClickBindAttribute", typeof(UIDoubleClickBindAttribute) },
            
            { "UIPointerDownBindAttribute", typeof(UIPointerDownBindAttribute) },
            { "UIPointerUpBindAttribute", typeof(UIPointerUpBindAttribute) },
            { "UIPointerEnterBindAttribute", typeof(UIPointerEnterBindAttribute) },
            { "UIPointerExitBindAttribute", typeof(UIPointerExitBindAttribute) },
            { "UIDragBindAttribute", typeof(UIDragBindAttribute) },
            { "UIBeginDragBindAttribute", typeof(UIBeginDragBindAttribute) },
            { "UIEndDragBindAttribute", typeof(UIEndDragBindAttribute) },
            { "UIScrollBindAttribute", typeof(UIScrollBindAttribute) },
            { "UISelectBindAttribute", typeof(UISelectBindAttribute) },
            { "UIDeselectBindAttribute", typeof(UIDeselectBindAttribute) },
            { "UISubmitBindAttribute", typeof(UISubmitBindAttribute) },
            { "UICancelBindAttribute", typeof(UICancelBindAttribute) }
        };

        public static void AutoBind(Component component)
        {
            var instanceId = component.GetInstanceID();
            // 防止重复绑定
            if (s_BindedComponents.Contains(instanceId))
            {
                Debug.LogWarning($"组件 {component.GetType().Name} 已经绑定过，避免重复绑定");
                return;
            }
            
            var type = component.GetType();
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
            
            // 按顺序处理不同类型的绑定
            foreach (var field in GetFieldsWithCache(type, flags))
            {
                BindGameObject(component, field);
            }
            
            foreach (var field in GetFieldsWithCache(type, flags))
            {
                BindCollection(component, field);
            }
            
            foreach (var field in GetFieldsWithCache(type, flags))
            {
                BindComponent(component, field);
            }
            
            foreach (var method in GetMethodsWithCache(type, flags))
            {
                UIButtonClickBind(component, method);
                UIToggleValueChangedBind(component, method);
                UISliderValueChangedBind(component, method);
                UIInputFieldValueChangedBind(component, method);
                UIDropdownValueChangedBind(component, method);
                UILongClickBind(component, method);
                UIDoubleClickBind(component, method);
                UIPointerDownBind(component, method);
                UIPointerUpBind(component, method);
                UIPointerEnterBind(component, method);
                UIPointerExitBind(component, method);
                UIBeginDragBind(component, method);
                UIDragBind(component, method);
                UIEndDragBind(component, method);
                UIScrollBind(component, method);
                UISelectBind(component, method);
                UIDeselectBind(component, method);
                UISubmitBind(component, method);
                UICancelBind(component, method);
            }
            
            s_BindedComponents.Add(instanceId);
        }

        public static void Unbind(Component component)
        {
            var instanceId = component.GetInstanceID();
            
            if (s_BindedUIComponents.ContainsKey(instanceId))
            {
                foreach (var componentRef in s_BindedUIComponents[instanceId])
                {
                    if (componentRef is not UnityEngine.Component uiComponent) continue;
                    if (uiComponent is UnityEngine.UI.Button button)
                    {
                        button.onClick.RemoveAllListeners();
                    }
                    else if (uiComponent is UnityEngine.UI.Toggle toggle)
                    {
                        toggle.onValueChanged.RemoveAllListeners();
                    }
                    else if (uiComponent is UnityEngine.UI.Slider slider)
                    {
                        slider.onValueChanged.RemoveAllListeners();
                    }
                    else if (uiComponent is UnityEngine.UI.InputField inputField)
                    {
                        inputField.onValueChanged.RemoveAllListeners();
                    }
                    else if (uiComponent is UnityEngine.UI.Dropdown dropdown)
                    {
                        dropdown.onValueChanged.RemoveAllListeners();
                    }
                    else if (uiComponent is LongPressEventComponent longPress)
                    {
                        longPress.RemoveAllListeners();
                    }
                    else if (uiComponent is DoubleClickEventComponent doubleClick)
                    {
                        doubleClick.RemoveAllListeners();
                    }
                    else if (uiComponent is EventTrigger eventTrigger)
                    {
                        eventTrigger.triggers.Clear();
                    }
                }
                s_BindedUIComponents.Remove(instanceId);
            }
            
            // 从已绑定组件集合中移除
            s_BindedComponents.Remove(instanceId);

            ClearPathCacheForComponent(component);
        }

        /// <summary>
        /// 清理所有缓存数据
        /// </summary>
        public static void Release()
        {
            s_BindedUIComponents.Clear();
            s_BindedComponents.Clear();
            s_CachedFields.Clear();
            s_CachedMethods.Clear();
            s_PathCache.Clear();
        }

        /// <summary>
        /// 记录绑定的UI组件，用于资源释放
        /// </summary>
        /// <param name="component">绑定的组件</param>
        /// <param name="uiComponent">UI组件引用</param>
        private static void RecordUIComponent(Component component, object uiComponent)
        {
            var instanceId = component.GetInstanceID();

            if (!s_BindedUIComponents.ContainsKey(instanceId))
            {
                s_BindedUIComponents[instanceId] = new List<object>();
            }

            if (!s_BindedUIComponents[instanceId].Contains(uiComponent))
            {
                s_BindedUIComponents[instanceId].Add(uiComponent);
            }
        }

        private static bool ValidateMethodSignature(MethodInfo method, Type returnType, Type[] parameterTypes)
        {
            if (method.ReturnType != returnType) return false;

            var parameters = method.GetParameters();
            if (parameters.Length != parameterTypes.Length) return false;

            return !parameters.Where((t, i) => t.ParameterType != parameterTypes[i]).Any();
        }

        private static FieldInfo[] GetFieldsWithCache(Type type, BindingFlags flags)
        {
            if (!s_CachedFields.ContainsKey(type))
            {
                s_CachedFields[type] = type.GetFields(flags);
            }

            return s_CachedFields[type];
        }

        private static MethodInfo[] GetMethodsWithCache(Type type, BindingFlags flags)
        {
            if (!s_CachedMethods.ContainsKey(type))
            {
                s_CachedMethods[type] = type.GetMethods(flags);
            }

            return s_CachedMethods[type];
        }

        private static T GetCustomAttributeWithCache<T>(MemberInfo member) where T : Attribute
        {
            var attributeType = typeof(T);
            if (!s_CachedTypes.TryGetValue(attributeType.Name, out var type)) return member.GetCustomAttribute<T>();
            var attr = member.GetCustomAttribute(type);
            return attr as T;
        }

        private static Transform FindTransformWithPathCache(Transform root, string path)
        {
            var cacheKey = $"{root.GetInstanceID()}_{path}";
            if (s_PathCache.TryGetValue(cacheKey, out var cachedTransform))
            {
                return cachedTransform;
            }

            var result = root.Find(path);
            if (result != null)
            {
                s_PathCache[cacheKey] = result;
            }

            return result;
        }

        private static void ClearPathCacheForComponent(Component component)
        {
            var prefix = $"{component.GetInstanceID()}_";
            var keysToRemove = (from kvp in s_PathCache where kvp.Key.StartsWith(prefix) select kvp.Key).ToList();

            foreach (var key in keysToRemove)
            {
                s_PathCache.Remove(key);
            }
        }
    }
}